home *** CD-ROM | disk | FTP | other *** search
-
- {
- This unit is based on the unit 'Dates' by Scott Bussinger. I liked what he
- did in his unit, but I was bothered by the fact that someone over the age of
- 89 years couldn't have their birthdate represented. I considered just moving
- his minimun year (1900) back 20 years, but then future dates were also limited.
- This unit will allow dates from 1/1/1583 to 12/31/2300, but you do pay a price
- for this enhanced capability, the dates are stored as three bytes instead of
- two as in the original dates unit. I think this enhanced version is worth the
- extra byte of storage. I have used 2 or 3 of his routines almost verbatim, but
- others are completely rewritten, or in some cases improved upon.
-
- NOTE: The minimum year 1583 is the absolute minimum, as the Gregorian calendar
- started that year (actually 10/15/1582). The maximum year of 2300 was
- arbitrarily picked by me. You can raise it several thousand years if you
- desire. The number indicating the days from 1/1/1583 (#1) is the MD number or
- Murphy Day, not to be confused with the JD number, the Julian Day which was
- devised by Joseph Scalinger in 1582.
-
- Jim Murphy [74030,2643]
- }
-
-
- unit dates3;
-
- interface
-
- uses dos;
-
- type
- str3=string[3];
- str9=string[9];
-
- const
- minyear=1583;
- maxyear=2300;
-
- monthstr:array[1..12] of str9=('January','February','March','April','May',
- 'June','July','August','September',
- 'October','November','December');
-
- daystr:array[0..6] of str9=('Sunday','Monday','Tuesday','Wednesday',
- 'Thursday','Friday','Saturday');
-
-
- function validdate(month,day,year:word):boolean;
- { Returns a TRUE if date is legal and within valid years }
- function daynumber(datenum:longint):word;
- { Returns the number of the day of week (0 to 6) for a given 'datenumber' }
- function daystring(daynum:word):str9;
- { Takes a daynumber and returns a string containing the day of the week }
- function monthstring(monthnum:word):str9;
- { Takes the month number (1 to 12) and returns a string containing the month }
- function datenumber(month,day,year:word):longint;
- { Takes the date (mm dd yyyy) and returns the datenumber for that date }
- procedure numberdate(datenum:longint; var month,day,year:word);
- { Converts the datenumber for a date and returns the Month, Day, Year }
- function today:longint;
- { Returns the datenumber for the present date }
- function agetoday(datenum:longint):word;
- { Takes the datenumber for a given date, and returns the Age today }
- function numstring(datenum:longint):str3;
- { Converts the datenumber to a sortable 3 byte string for database storage }
- function stringnum(numstr:string):longint;
- { Converts the 3 byte sortable string back to the original datenumber }
- function bumpdate(datenum:longint; months,days,years:integer):longint;
- { Returns the NEW datenumber for a given datenumber that is increased/decreased
- by user selected values. Example: -2 for years, decreases the years by two }
-
- implementation
-
- const
- months:array[1..12] of word=(31,59,90,120,151,181,212,243,273,304,334,365);
-
- type
- intstr=array[0..3] of byte;
-
- function isleap(year:word):boolean;
- { This is used internally only by the other procedures/functions }
- begin
- isleap:=false;
- if year mod 100=0 then isleap:=year mod 400=0 else
- isleap:=year mod 4=0;
- end;
-
- function daynumber(datenum:longint):word;
- begin
- daynumber:=(datenum+5) mod 7;
- end;
-
- function daystring(daynum:word):str9;
- begin
- daystring:=daystr[daynum];
- end;
-
- function monthstring(monthnum:word):str9;
- begin
- monthstring:=monthstr[monthnum];
- end;
-
- function validdate(month,day,year:word):boolean;
- begin
- validdate:=false;
- if (month>=1) and (month<=12) then begin
- if (year>=minyear) and (year<=maxyear) then begin
- if day>=1 then begin
- case month of
- 1,3,5,7,8,10,12:validdate:=day<=31;
- 4,6,9,11:validdate:=day<=30;
- 2:if isleap(year) then validdate:=day<=29 else
- validdate:=day<=28;
- end;
- end;
- end;
- end;
- end;
-
- function datenumber(month,day,year:word):longint;
- var i:word; temp:longint;
- begin
- temp:=0;
- if year>minyear then begin
- for i:=minyear to year-1 do
- temp:=temp+365+(1*ord(isleap(i)));
- end;
- if month>2 then begin
- temp:=temp+months[month-1]+day+1*ord(isleap(year));
- end else temp:=temp+day+(31*ord(month>1));
- datenumber:=temp;
- end;
-
- procedure numberdate(datenum:longint; var month,day,year:word);
- var i:word; temp:longint; finished,leap:boolean;
- begin
- temp:=0; i:=minyear-1; finished:=false;
- repeat
- inc(i);
- temp:=temp+365+1*ord(isleap(i));
- if temp>=datenum then begin
- temp:=temp-(365+1*ord(isleap(i)));
- temp:=datenum-temp;
- finished:=true;
- end;
- until finished or (i>=maxyear);
- year:=i;
- leap:=isleap(year);
- i:=1; finished:=false;
- while not finished and (i<=12) do begin
- if months[i]+1*((ord(leap)) and (ord(i>1))) >=temp then begin
- month:=i;
- if month>2 then begin
- day:=temp-(months[i-1]+1*((ord(leap)) and (ord(i-1>1))));
- end else day:=temp-(31*ord(month>1));
- finished:=true;
- end;
- inc(i);
- end;
- end;
-
- function today:longint;
- var year,month,day,daynum:word;
- begin
- getdate(year,month,day,daynum);
- today:=datenumber(month,day,year);
- end;
-
- function agetoday(datenum:longint):word;
- var tmonth,tday,tyear,bmonth,bday,byear,age:word;
- begin
- numberdate(datenum,bmonth,bday,byear);
- numberdate(today,tmonth,tday,tyear);
- age:=tyear-byear;
- if (tmonth<bmonth) or ((tmonth=bmonth) and (tday<bday)) then dec(age);
- agetoday:=age;
- end;
-
- function numstring(datenum:longint):str3;
- var datestr:intstr absolute datenum; i:byte; temp:str3;
- begin
- for i:=0 to 2 do
- temp[3-i]:=chr(datestr[i]);
- temp[0]:=#3;
- numstring:=temp;
- end;
-
- function stringnum(numstr:string):longint;
- var temp:intstr; datenum:longint absolute temp; i:byte;
- begin
- for i:=0 to 2 do
- temp[2-i]:=ord(numstr[i+1]);
- temp[3]:=0;
- stringnum:=datenum;
- end;
-
- function bumpdate(datenum:longint; months,days,years:integer):longint;
- { I fixed some problems in the original dates unit. If you subtract or add
- one year from 2/29/1600 (a leap year) for example, you will get 3/1/1599
- or 3/1/1601. This is a correct date considering there is no Feb. 29 in
- either of the two years. Also any date that exceeds 2300 or is smaller
- than 1583 will not change the year, just the month/day numbers. }
- var month,day,year:word; temp:longint; tmonth:integer;
- begin
- numberdate(datenum,month,day,year);
- tmonth:=month;
- tmonth:=tmonth+months-1;
- year:=year+years+(tmonth div 12)-ord(tmonth<0);
- tmonth:=(tmonth+12000) mod 12+1;
- month:=tmonth;
- temp:=datenumber(month,day,year)+days;
- numberdate(temp,month,day,year);
- bumpdate:=datenumber(month,day,year);
- end;
-
- end.